<?php

namespace Services\Ai;

use Common\Model\Ai\AiTaskModel;
use Services\Ai\Exceptions\AiException;
use Services\BaseService;
use Services\Request\CozeRequest;

class AiService extends BaseService
{
    const CHANNEL_COZE = 'coze'; //火山引擎-扣子渠道
    const AUTH_PERSONAL = 'personal';
    /** @var AiTaskModel $model */
    private $model;

    public function __construct()
    {
        $this->model = new AiTaskModel();
    }

    /**
     * 发起对话
     * @return null[]|string[]
     * @throws AiException
     */
    public function chat(): array
    {
        $params = $this->getParams();
        $checkParams = [
            'type' => '智能体类型',
            'form' => '表单',
            'length' => '内容长度',
        ];
        foreach ($checkParams as $key => $item) {
            if (empty($params[$key])) {
                throw new AiException(sprintf('%s,参数不能为空', $item));
            }
        }
        $channel = $this->getParam('channel', self::CHANNEL_COZE);
        $taskId = '';
        if ($channel == self::CHANNEL_COZE) {
            $taskId = $this->cozeChat();
        }

        return [
            'task_id' => $taskId
        ];
    }

    /**
     * 提示词转换
     * @return string
     * @throws AiException
     */
    private function getCallWord()
    {

        $form = $this->getParam('form', []);
        $aiItemConfig = $this->getAiItemConfig();
        $aiItemConfigForm = arr_get($aiItemConfig, 'form', []);
        $callWord = '';
        foreach ($aiItemConfigForm as $key => $item) {
            if ($item['type'] == AiList::FORM_ENUM) {
                continue;
            }
            $callWord .= sprintf('%s:%s ', $item['label'], $form[$item['name']]);
        }
        return $callWord;
    }

    /**
     * 获取对应的ai智能体配置
     * @return mixed
     * @throws AiException
     */
    private function getAiItemConfig()
    {
        $type = $this->getParam('type');
        $aiItemConfig = [];
        foreach (AiList::AI_LIST as $item) {
            if (arr_get($item, 'type') == $type) {
                $aiItemConfig = $item;
            }
        }
        if (empty($aiItemConfig)) {
            throw new AiException(sprintf('type:%s,未找到对应的ai配置', $type));
        }
        return $aiItemConfig;
    }

    /**
     * 扣子的调用
     * @return void
     * @throws AiException
     */
    private function cozeChat()
    {
        $params = $this->getParams();
        //依据类型构造智能体请求提示词
        $aiItemConfig = $this->getAiItemConfig();
        $callWord = $this->getCallWord();
        $params['content'] = $callWord;
        //发送请求
        $request = (new CozeRequest());
        $result = $request->chat([
            'bot_id' => arr_get($aiItemConfig, 'coze_bot_id'),
            'user_id' => $params['user_id'],
            'content' => $params['content'],
        ]);
        $taskId = '';
        if ($result) {
            $taskId = AiTaskModel::generateTaskId();
            $params['params'] = $params;
            $params['platform'] = AiTaskModel::PLATFORM_COZE;
            $params['status'] = AiTaskModel::STATUS_RUNNING;
            $params['coze_chat_id'] = arr_get($result, 'id', '');
            $params['coze_conversation_id'] = arr_get($result, 'conversation_id', '');
            $params['task_id'] = $taskId;
            $this->addTask($params);
        }
        return $taskId;
    }
    //===========================chat end=========================================
    //===========================任务记录=========================================

    /**
     * 获取任务的详情
     * @param $userId
     * @param $taskId
     * @return void
     */
    public function getTaskInfo($userId,$taskId){
        $task = $this->model->where([
            'user_id' => $userId,
            'task_id' => $taskId
        ])->field('params',true)->find();
        if($task){
            $task['result'] = json_decode($task['result'],true);
        }
        return $task;
    }
    public function addTask($data = [])
    {
        return $this->model->add([
            'user_id' => arr_get($data, 'user_id'),
            'task_id' => arr_get($data, 'task_id'),
            'status' => arr_get($data, 'status', AiTaskModel::STATUS_WAITTING),
            'platform' => arr_get($data, 'platform'),
            'coze_chat_id' => arr_get($data, 'coze_chat_id'),
            'coze_conversation_id' => arr_get($data, 'coze_conversation_id'),
            'params' => json_encode(arr_get($data, 'params', []), JSON_UNESCAPED_UNICODE),
            'created_at' => get_now_date(),
            'updated_at' => get_now_date(),
        ]);
    }

    public function setSuccess($id, $attributes = [])
    {
        $saveData = array_merge([
            'status' => AiTaskModel::STATUS_SUCCESS,
        ], $attributes);
        return $this->model->where([
            'id' => $id
        ])->save($saveData);
    }

    public function setFailed($id, $attributes = [])
    {
        $saveData = array_merge([
            'status' => AiTaskModel::STATUS_FAILED,
        ], $attributes);
        return $this->model->where([
            'id' => $id
        ])->save($saveData);
    }

    public function setRunning($id, $attributes = [])
    {
        $saveData = array_merge([
            'status' => AiTaskModel::STATUS_RUNNING,
        ], $attributes);
        return $this->model->where([
            'id' => $id
        ])->save($saveData);
    }

    //===========================结果获取=========================================

    public function taskResultGet()
    {
        while (true) {
            $tasks = $this->model->where([
                'status' => AiTaskModel::STATUS_RUNNING,
            ])->select();
            foreach ($tasks as $task) {
                $this->singleTaskResult($task);
            }
            sleep(1);
        }
        return true;
    }

    /**
     * 获取结果
     * @param $task
     * @return void
     * @throws \Exception
     */
    public function singleTaskResult($task = [])
    {
        switch ($task['platform']) {
            case AiTaskModel::PLATFORM_COZE:
                $this->cozeResult($task);
                break;
        }
        return true;
    }

    private function cozeResult(array $task)
    {
        //todo:根据不同的平台获取ai对话任务的结果
        //发送请求
        $request = (new CozeRequest());
        $retrieveResult = $request->retrieve([
            'conversation_id' => arr_get($task, 'coze_conversation_id'),
            'chat_id' => arr_get($task, 'coze_chat_id'),
        ]);
        if ($retrieveResult['status'] == CozeRequest::RETRIEVE_COMPLETED) {
            $this->setRunning($task['id'], [
                'coze_usage' => json_encode(arr_get($retrieveResult, 'usage', '')),
            ]);

            //请求消息列表获取结果
            $messageResult = $request->message(arr_get($task, 'coze_conversation_id'), arr_get($task, 'coze_chat_id'));
            if(is_array($messageResult)){
                $saveResult = [
                    'content' => '',
                    'follow_tips' => []
                ];
                foreach ($messageResult as $item) {
                    if ($item['type'] == 'answer') {
                        $saveResult['content'] = $item['content'] ?? '未知结果';
                    }

                    if ($item['type'] == 'follow_up') {
                        $saveResult['follow_tips'][] = $item['content'] ?? '未知结果';
                    }
                }
               $this->setSuccess($task['id'], [
                   'result' => json_encode($saveResult,JSON_UNESCAPED_UNICODE)
               ]);
            }
        } elseif ($retrieveResult['status'] == CozeRequest::RETRIEVE_FAILED) {
            if (!empty($result['last_error'])) {
                $this->setFailed($task['id'], [
                    'errmsg' => json_encode($result['last_error'])
                ]);
            }
        }

        return true;
    }
}
